package com.xuecheng.media.service.impl;

import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.vod.model.v20170321.CreateUploadVideoResponse;
import com.aliyuncs.vod.model.v20170321.GetPlayInfoResponse;
import com.aliyuncs.vod.model.v20170321.RefreshUploadVideoResponse;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xuecheng.api.content.model.dto.TeachplanMediaDTO;
import com.xuecheng.api.media.model.ResourceUrlModel;
import com.xuecheng.api.media.model.VodUploadRequest;
import com.xuecheng.api.media.model.VodUploadToken;
import com.xuecheng.api.media.model.dto.MediaDTO;
import com.xuecheng.api.media.model.qo.QueryMediaModel;
import com.xuecheng.common.domain.code.CommonErrorCode;
import com.xuecheng.common.domain.page.PageRequestParams;
import com.xuecheng.common.domain.page.PageVO;
import com.xuecheng.common.domain.response.RestResponse;
import com.xuecheng.common.enums.common.AuditEnum;
import com.xuecheng.common.enums.common.CommonEnum;
import com.xuecheng.common.enums.common.ResourceTypeEnum;
import com.xuecheng.common.exception.ExceptionCast;
import com.xuecheng.media.agent.ContentApiAgent;
import com.xuecheng.media.common.constant.MediaErrorCode;
import com.xuecheng.media.common.utils.AliyunVODUtil;
import com.xuecheng.media.convert.MediaConvert;
import com.xuecheng.media.entity.Media;
import com.xuecheng.media.mapper.MediaMapper;
import com.xuecheng.media.service.MediaService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;

import java.time.Duration;
import java.time.LocalDateTime;
import java.util.Collections;
import java.util.List;


/**
 * Created on 2021/04/03/23:13 周六
 *
 * @author Lantin
 */
@Service
@Slf4j
public class MediaServiceImpl extends ServiceImpl<MediaMapper, Media> implements MediaService {

    @Autowired
    private DefaultAcsClient client;

    @Autowired
    private ContentApiAgent contentApiAgent;


    /**
     * <p>
     * 获取视频上传地址和凭证
     * </p>
     *
     * @param vodUploadRequest 视频上传请求参数
     * @return VodUploadToken
     */
    @Override
    public VodUploadToken createVODUploadToken(VodUploadRequest vodUploadRequest) {

        if (ObjectUtils.isEmpty(vodUploadRequest)) {
            ExceptionCast.cast(CommonErrorCode.E_100116);
        }
        String fileName = vodUploadRequest.getFileName();
        String title = vodUploadRequest.getTitle();
        if (StringUtils.isEmpty(fileName) ||
                StringUtils.isEmpty(title)) {
            ExceptionCast.cast(MediaErrorCode.E_140006);
        }


        try {
            CreateUploadVideoResponse response = AliyunVODUtil.createUploadVideo(client, title, fileName);
            return new VodUploadToken(response.getRequestId(),
                    response.getVideoId(), null,
                    response.getUploadAddress(),
                    response.getUploadAuth());
        } catch (Exception e) {
            ExceptionCast.cast(MediaErrorCode.E_140011);

        }
        return null;
    }

    /**
     * <p>
     * 刷新视频上传凭证
     * </p>
     *
     * @param videoId 视频id
     * @return VodUploadToken
     */
    @Override
    public VodUploadToken refreshVODUploadToken(String videoId) {

        if (StringUtils.isEmpty(videoId)) {
            ExceptionCast.cast(MediaErrorCode.E_140007);
        }

        try {
            RefreshUploadVideoResponse response = AliyunVODUtil.refreshUploadVideo(client, videoId);
            return new VodUploadToken(response.getRequestId(),
                    response.getVideoId(), null,
                    response.getUploadAddress(),
                    response.getUploadAuth());
        } catch (Exception e) {
            ExceptionCast.cast(MediaErrorCode.E_140015);
        }
        return null;
    }

    /**
     * <p>
     * 分页查询媒资信息
     * </p>
     *
     * @param params    分页参数
     * @param model     查询参数
     * @param companyId 机构id
     * @return PageVO<MediaDTO>
     */
    @Override
    public PageVO<MediaDTO> queryMediaList(PageRequestParams params, QueryMediaModel model, Long companyId) {

        if (ObjectUtils.isEmpty(params)) {
            params = new PageRequestParams();
        }
        Integer pageSize = params.getPageSize();
        Long pageNo = params.getPageNo();

        if (ObjectUtils.isEmpty(pageSize) || pageSize < 1) {
            pageSize = PageRequestParams.DEFAULT_PAGE_SIZE;
        }
        if (ObjectUtils.isEmpty(pageNo) || pageNo < 1) {
            pageNo = PageRequestParams.DEFAULT_PAGE_NUM;
        }
        //构建分页对象
        Page<Media> pageRequest = new Page<>(pageNo, pageSize);
        //构建条件查询
        LambdaQueryWrapper<Media> queryWrapper = Wrappers.lambdaQuery(Media.class);
        queryWrapper.like(StringUtils.isNotBlank(model.getFilename()), Media::getFilename, model.getFilename());
        queryWrapper.eq(StringUtils.isNotBlank(model.getType()), Media::getType, model.getType());
        String auditStatus = model.getAuditStatus();

        queryWrapper.eq(StringUtils.isNotBlank(auditStatus), Media::getAuditStatus, model.getAuditStatus());

        queryWrapper.eq(!ObjectUtils.isEmpty(companyId), Media::getCompanyId, companyId);
        queryWrapper.eq(Media::getStatus, CommonEnum.USING_FLAG.getCode());

        Page<Media> result = this.page(pageRequest, queryWrapper);

        List<Media> records = result.getRecords();
        List<MediaDTO> dtoList = Collections.emptyList();

        if (CollectionUtils.isNotEmpty(records)) {
            dtoList = MediaConvert.INSTANCE.mediaToDTOList(records);
        }
        PageVO<MediaDTO> pageVO = new PageVO<>(result.getTotal(), pageNo, pageSize);
        pageVO.setItems(dtoList);
        return pageVO;
    }


    /**
     * <p>
     * 存入媒资数据信息
     * </p>
     *
     * @param mediaDTO  媒资信息数据
     * @param companyId 机构id
     * @return MediaDTO
     */
    @Override
    @Transactional
    public MediaDTO createMedia(MediaDTO mediaDTO, Long companyId) {

        if (StringUtils.isBlank(mediaDTO.getFileId())) {
            ExceptionCast.cast(MediaErrorCode.E_140007);
        }
        if (StringUtils.isBlank(mediaDTO.getFilename())) {
            ExceptionCast.cast(MediaErrorCode.E_140006);
        }
        if (StringUtils.isBlank(mediaDTO.getType())) {
            ExceptionCast.cast(MediaErrorCode.E_140008);
        }

        Media media = MediaConvert.INSTANCE.dtoToMedia(mediaDTO);
        media.setAuditStatus(AuditEnum.AUDIT_UNPAST_STATUS.getCode());
        media.setCompanyId(companyId);

        //如果媒资为视频，则获取播放地址
        String type = mediaDTO.getType();
        if (ResourceTypeEnum.VIDEO.getCode().equals(type)) {
            String playUrl = getPlayUrl(media.getFileId());
            media.setUrl(playUrl);
        }
        boolean save = this.save(media);
        if (!save) {
            ExceptionCast.cast(MediaErrorCode.E_140001);
        }
        return MediaConvert.INSTANCE.mediaToDTO(media);
    }

    private String getPlayUrl(String videoId) {
        try {
            GetPlayInfoResponse playInfoResponse = AliyunVODUtil.getPlayInfo(client, videoId);
            List<GetPlayInfoResponse.PlayInfo> playInfoList = playInfoResponse.getPlayInfoList();

            return playInfoList.get(0).getPlayURL();
        } catch (Exception e) {
            ExceptionCast.castWithException(MediaErrorCode.E_140012, e);
        }
        return null;
    }

    /**
     * <p>
     * 根据id查询媒资信息
     * 微服务远程调用
     * </p>
     *
     * @param mediaId 媒资id
     * @return RestResponse
     */
    @Override
    public RestResponse<MediaDTO> getByMediaId(Long mediaId) {

        if (ObjectUtils.isEmpty(mediaId)) {
            return RestResponse.validfail(CommonErrorCode.E_110006);
        }
        Media media = this.getById(mediaId);

        if (ObjectUtils.isEmpty(media)) {
            return RestResponse.validfail(MediaErrorCode.E_140005);
        }

        MediaDTO mediaDTO = MediaConvert.INSTANCE.mediaToDTO(media);

        return RestResponse.success(mediaDTO);
    }

    /**
     * <p>
     * 预览媒资视频
     * </p>
     *
     * @param mediaId   媒资信息id
     * @param companyId 机构id
     * @return MediaDTO
     */
    @Override
    public String previewMedia(Long mediaId, Long companyId) {

        Media media = verifyMediaInfo(mediaId, companyId);
        String type = media.getType();
        String url = media.getUrl();
        //如果媒资是视频 校验播放地址有效性
        if (ResourceTypeEnum.VIDEO.getCode().equals(type)) {
            url = urlValidation(media);
        }
        return url;
    }

    /**
     * <p>
     * 根据mediaId获取媒资播放url
     * </p>
     *
     * @param mediaId 媒资id
     * @return RestResponse<ResourceUrlModel>
     */
    @Override
    public RestResponse<ResourceUrlModel> getMediaUrl(Long mediaId) {

        Media media = this.getById(mediaId);

        if (ObjectUtils.isEmpty(media)) {
            return RestResponse.validfail(MediaErrorCode.E_140005);
        }
        String type = media.getType();
        String url = media.getUrl();
        //如果媒资是视频 校验播放地址有效性
        if (ResourceTypeEnum.VIDEO.getCode().equals(type)) {
            try {
                url = urlValidation(media);
            } catch (Exception e) {
               return RestResponse.validfail(MediaErrorCode.E_140012);
            }
        }
        ResourceUrlModel resourceUrlModel = new ResourceUrlModel();
        resourceUrlModel.setPlayUrl(url);
        resourceUrlModel.setState(Integer.parseInt(media.getStatus()));

        return RestResponse.success(resourceUrlModel);

    }

    private String urlValidation(Media media) {
        String url = media.getUrl();
        LocalDateTime changeDate = media.getChangeDate();

        LocalDateTime urlCreateTime;

        if (!ObjectUtils.isEmpty(changeDate)) {
            urlCreateTime = changeDate;
        } else {
            urlCreateTime = media.getCreateDate();
        }
        //如果url过期则重新获取url
        long expireIn = 3600 - Duration.between(urlCreateTime, LocalDateTime.now()).getSeconds();
        if (expireIn < 30) {
            log.info(MediaErrorCode.E_140013.getDesc() + " expireTime:" + expireIn + " ==>执行向阿里云获取新的播放地址");
            url = getPlayUrl(media.getFileId());
            media.setChangeDate(LocalDateTime.now());
            media.setUrl(url);
            boolean update = this.updateById(media);
            if (!update) {
                ExceptionCast.cast(MediaErrorCode.E_140018);
            }
        }
        return url;
    }

    /**
     * <p>
     * 删除媒资信息数据
     * </p>
     *
     * @param mediaId   媒资数据id
     * @param companyId 机构id
     * @return boolean
     */
    @Override
    @Transactional
    public boolean deleteMedia(Long mediaId, Long companyId) {
        Media media = verifyMediaInfo(mediaId, companyId);

        media.setStatus(CommonEnum.DELETE_FLAG.getCode());

        //判断当前媒资是否有绑定
        RestResponse<List<TeachplanMediaDTO>> response = contentApiAgent.getTeachplanMediaById(mediaId);

        if (!response.isSuccessful()) {
            ExceptionCast.cast(CommonErrorCode.E_999981);
        }
        List<TeachplanMediaDTO> dtoList = response.getResult();
        if (CollectionUtils.isNotEmpty(dtoList)) {
            ExceptionCast.cast(MediaErrorCode.E_140003);
        }

        media.setStatus(CommonEnum.DELETE_FLAG.getCode());
        boolean update = this.updateById(media);
        if (!update) {
            ExceptionCast.cast(MediaErrorCode.E_140002);
        }
        return true;
    }

    private Media verifyMediaInfo(Long mediaId, Long companyId) {
        if (ObjectUtils.isEmpty(mediaId)) {
            ExceptionCast.cast(CommonErrorCode.E_110006);
        }
        Media media = this.getById(mediaId);


        if (ObjectUtils.isEmpty(media)) {
            ExceptionCast.cast(MediaErrorCode.E_140005);
        }
        //companyId不为空才校验机构
        if (!ObjectUtils.isEmpty(companyId)) {
            if (!ObjectUtils.nullSafeEquals(companyId, media.getCompanyId())) {
                ExceptionCast.cast(CommonErrorCode.E_100108);
            }
        }
        return media;
    }

    /**
     * <p>
     * 审核媒资信息
     * </p>
     *
     * @param mediaId     媒资id
     * @param auditStatus 审核状态
     * @param auditMind   审核意见
     * @return boolean
     */
    @Override
    public boolean auditMedia(Integer mediaId, String auditStatus, String auditMind) {

        if (ObjectUtils.isEmpty(mediaId)) {
            ExceptionCast.cast(CommonErrorCode.E_110006);
        }

        Media media = this.getById(mediaId);
        if (ObjectUtils.isEmpty(media)) {
            ExceptionCast.cast(MediaErrorCode.E_140005);
        }
        //被审核的媒资状态只能为未审核
        if (!StringUtils.equals(media.getAuditStatus(), AuditEnum.AUDIT_UNPAST_STATUS.getCode())) {
            ExceptionCast.cast(MediaErrorCode.E_140017);
        }

        if (!StringUtils.equals(auditStatus, AuditEnum.AUDIT_PASTED_STATUS.getCode()) &&
                !StringUtils.equals(auditStatus, AuditEnum.AUDIT_DISPAST_STATUS.getCode())) {
            ExceptionCast.cast(MediaErrorCode.E_140016);
        }
        if (!ObjectUtils.isEmpty(auditMind)) {
            media.setAuditMind(auditMind);
        }
        media.setAuditStatus(auditStatus);
        boolean update = this.updateById(media);
        if (!update) {
            ExceptionCast.cast(MediaErrorCode.E_140018);
        }
        return true;
    }
}
